﻿using System;
using System.Collections.Generic;
using System.Linq;
using BusinessLogic.Configuration;
using BusinessLogic.Configuration.Settings;
using BusinessLogic.EmployeeManagement;
using BusinessLogic.Infrastructure;
using Common;
using Common.Utils;
using System.Web;
using System.Globalization;
using System.Threading;
using BusinessLogic.Directory;

namespace BusinessLogic
{
    public partial class PayrollContext
    {
         #region Constants
        private const string CONST_CUSTOMERSESSION = "Payroll.EmployeeSession";
        private const string CONST_CUSTOMERSESSIONCOOKIE = "Payroll.EmployeeSessionGUIDCookie";
        #endregion

        #region Fields
        private Employee _currentCustomer;
        private bool _isCurrentCustomerImpersonated;
        private Employee _originalCustomer;
        private Language _workingLanguage;
        private bool? _isAdmin;
        private readonly HttpContext m_context = HttpContext.Current;
        #endregion

        #region Ctor
        /// <summary>
        /// Creates a new instance of the PayrollContext class
        /// </summary>
        private PayrollContext()
        {
        }
        #endregion

        #region Methods

        /// <summary>
        /// Save customer session to data source
        /// </summary>
        /// <returns>Saved customer ssion</returns>
        private EmployeeSession SaveSessionToDatabase()
        {
            var sessionId = Guid.NewGuid();
            while (IoC.Resolve<IEmployeeService>().GetEmployeeSessionByGuid(sessionId) != null)
                sessionId = Guid.NewGuid();
            var session = new EmployeeSession();
            int employeeId = 0;
            if (this.User != null)
            {
                employeeId = this.User.EmployeeId;
            }
            session.EmployeeSessionGuid = sessionId;
            session.EmployeeId = employeeId;
            session.LastAccessed = DateTime.UtcNow;
            session.IsExpired = false;
            session = IoC.Resolve<IEmployeeService>().SaveCustomerSession(session.EmployeeSessionGuid, session.EmployeeId, session.LastAccessed, session.IsExpired);
            return session;
        }

        /// <summary>
        /// Gets the session.
        /// </summary>
        /// <param name="createInDatabase">if set to <c>true</c> [create in database].</param>
        /// <returns></returns>
        public EmployeeSession GetSession(bool createInDatabase)
        {
            return this.GetSession(createInDatabase, null);
        }

        /// <summary>
        /// Gets customer session
        /// </summary>
        /// <param name="createInDatabase">Create session in database if no one exists</param>
        /// <param name="sessionId">Session identifier</param>
        /// <returns>Customer session</returns>
        public EmployeeSession GetSession(bool createInDatabase, Guid? sessionId)
        {
            EmployeeSession byId = null;
            object obj2 = Current[CONST_CUSTOMERSESSION];
            if (obj2 != null)
                byId = (EmployeeSession)obj2;
            if ((byId == null) && (sessionId.HasValue))
            {
                byId = IoC.Resolve<IEmployeeService>().GetEmployeeByGuid(sessionId.Value);
                return byId;
            }
            if (byId == null && createInDatabase)
            {
                byId = SaveSessionToDatabase();
            }
            string customerSessionCookieValue = string.Empty;
            if ((HttpContext.Current.Request.Cookies[CONST_CUSTOMERSESSIONCOOKIE] != null) && (HttpContext.Current.Request.Cookies[CONST_CUSTOMERSESSIONCOOKIE].Value != null))
                customerSessionCookieValue = HttpContext.Current.Request.Cookies[CONST_CUSTOMERSESSIONCOOKIE].Value;
            if ((byId) == null && (!string.IsNullOrEmpty(customerSessionCookieValue)))
            {
                var dbCustomerSession = IoC.Resolve<IEmployeeService>().GetEmployeeByGuid(new Guid(customerSessionCookieValue));
                byId = dbCustomerSession;
            }
            Current[CONST_CUSTOMERSESSION] = byId;
            return byId;
        }

        /// <summary>
        /// Saves current session to client
        /// 
        /// </summary>
        public void SessionSaveToClient()
        {
            if (HttpContext.Current != null && this.Session != null)
                SetCookie(HttpContext.Current.ApplicationInstance, CONST_CUSTOMERSESSIONCOOKIE, this.Session.EmployeeSessionGuid.ToString());
        }

        /// <summary>
        /// Reset customer session
        /// </summary>
        public void ResetSession()
        {
            if (HttpContext.Current != null)
                SetCookie(HttpContext.Current.ApplicationInstance, CONST_CUSTOMERSESSIONCOOKIE, string.Empty);
            this.Session = null;
            this.User = null;
            this["Payroll.SessionReseted"] = true;
        }

        /// <summary>
        /// Sets cookie
        /// </summary>
        /// <param name="application">Application</param>
        /// <param name="key">Key</param>
        /// <param name="val">Value</param>
        private static void SetCookie(HttpApplication application, string key, string val)
        {
            HttpCookie cookie = new HttpCookie(key) { Value = val };
            if (string.IsNullOrEmpty(val))
            {
                cookie.Expires = DateTime.Now.AddMonths(-1);
            }
            else
            {
                cookie.Expires = DateTime.Now.AddHours(PayrollConfig.CookieExpires);
            }
            application.Response.Cookies.Remove(key);
            application.Response.Cookies.Add(cookie);
        }
        
        #endregion

        #region Properties

        /// <summary>
        /// Gets an instance of the PayrollContext, which can be used to retrieve information about current context.
        /// </summary>
        public static PayrollContext Current
        {
            get
            {
                if (HttpContext.Current == null)
                {
                    object data = Thread.GetData(Thread.GetNamedDataSlot("PayrollContext"));
                    if (data != null)
                    {
                        return (PayrollContext)data;
                    }
                    PayrollContext context = new PayrollContext();
                    Thread.SetData(Thread.GetNamedDataSlot("PayrollContext"), context);
                    return context;
                }
                if (HttpContext.Current.Items["PayrollContext"] == null)
                {
                    PayrollContext context = new PayrollContext();
                    HttpContext.Current.Items.Add("PayrollContext", context);
                    return context;
                }
                return (PayrollContext)HttpContext.Current.Items["PayrollContext"];
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether the context is running in admin-mode
        /// </summary>
        public bool IsAdmin
        {
            get
            {
                if (!_isAdmin.HasValue)
                {
                    _isAdmin = CommonHelper.IsAdmin();
                }
                return _isAdmin.Value;
            }
            set
            {
                _isAdmin = value;
            }
        }

        /// <summary>
        /// Gets or sets an object item in the context by the specified key.
        /// </summary>
        /// <param name="key">The key of the value to get.</param>
        /// <returns>The value associated with the specified key.</returns>
        public object this[string key]
        {
            get
            {
                if (this.m_context == null)
                {
                    return null;
                }

                if (this.m_context.Items[key] != null)
                {
                    return this.m_context.Items[key];
                }
                return null;
            }
            set
            {
                if (this.m_context != null)
                {
                    this.m_context.Items.Remove(key);
                    this.m_context.Items.Add(key, value);

                }
            }
        }

        /// <summary>
        /// Gets or sets the current session
        /// </summary>
        public EmployeeSession Session
        {
            get
            {
                return this.GetSession(false);
            }
            set
            {
                Current[CONST_CUSTOMERSESSION] = value;
            }
        }

        /// <summary>
        /// Gets or sets the current user
        /// </summary>
        public Employee User
        {
            get
            {
                return this._currentCustomer;
            }
            set
            {
                this._currentCustomer = value;
            }
        }
        
        /// <summary>
        /// Gets or sets the value indicating whether current user is impersonated
        /// </summary>
        public bool IsCurrentCustomerImpersonated
        {
            get
            {
                return this._isCurrentCustomerImpersonated;
            }
            set
            {
                this._isCurrentCustomerImpersonated = value;
            }
        }

        /// <summary>
        /// Gets or sets the current user (in case th current user is impersonated)
        /// </summary>
        public Employee OriginalUser
        {
            get
            {
                return this._originalCustomer;
            }
            set
            {
                this._originalCustomer = value;
            }
        }

        /// <summary>
        /// Gets an user host address
        /// </summary>
        public string UserHostAddress
        {
            get
            {
                if (HttpContext.Current != null &&
                    HttpContext.Current.Request != null &&
                    HttpContext.Current.Request.UserHostAddress != null)
                    return HttpContext.Current.Request.UserHostAddress;
                else
                    return string.Empty;
            }
        }

        /// <summary>
        /// Get or set current theme (e.g. darkOrange)
        /// </summary>
        public string WorkingTheme
        {
            get
            {
                if (IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Display.AllowCustomerSelectTheme"))
                {
                    string themeCookie = CommonHelper.GetCookieString("Payroll.WorkingTheme", false);
                    if (!String.IsNullOrEmpty(themeCookie))
                    {
                        //validate whether folder theme physically exists
                        string[] systemThemes = IoC.Resolve<ISettingManager>().GetSettingValue("Display.SystemThemes").Split(',');
                        var tmp1 = from f in System.IO.Directory.GetDirectories(HttpContext.Current.Request.PhysicalApplicationPath + "App_Themes")
                                        where !systemThemes.Contains(System.IO.Path.GetFileName(f).ToLower())
                                        && themeCookie.Equals(System.IO.Path.GetFileName(f), StringComparison.InvariantCultureIgnoreCase)
                                        select System.IO.Path.GetFileName(f);
                        if (tmp1.ToList().Count > 0)
                            return themeCookie;
                    }
                }
                string defaultTheme = IoC.Resolve<ISettingManager>().GetSettingValue("Display.PublicStoreTheme");
                if (!String.IsNullOrEmpty(defaultTheme))
                {
                    return defaultTheme;
                }
                return string.Empty;
            }
            set
            {
                if (!IoC.Resolve<ISettingManager>().GetSettingValueBoolean("Display.AllowCustomerSelectTheme"))
                    return;

                CommonHelper.SetCookie("Payroll.WorkingTheme", value.Trim(), new TimeSpan(365, 0, 0, 0, 0));
            }
        }
        /// <summary>
        /// Get or set current user working language
        /// </summary>
        public Language WorkingLanguage
        {
            get
            {
                //cached value
                if (this._workingLanguage != null)
                    return this._workingLanguage;

                //customer language
                if (this.User != null)
                {
                    var customerLanguage = this.User.Language;
                    if (customerLanguage != null && customerLanguage.Published)
                    {
                        this._workingLanguage = customerLanguage;
                        return this._workingLanguage;
                    }
                }
                else if (CommonHelper.GetCookieInt("Payroll.EmployeeLanguage") > 0)
                {
                    var employeeLanguage = IoC.Resolve<ILanguageService>().GetLanguageById(CommonHelper.GetCookieInt("Payroll.EmployeeLanguage"));
                    if (employeeLanguage != null && employeeLanguage.Published)
                    {
                        this._workingLanguage = employeeLanguage;
                        return this._workingLanguage;
                    }
                }
                var publishedLanguages = IoC.Resolve<ILanguageService>().GetAllLanguages(false);
                foreach (var language in publishedLanguages)
                {
                    this._workingLanguage = language;
                    return this._workingLanguage;
                }

                throw new PayrollException("Languages could not be loaded");
            }
            set
            {
                if (value == null)
                    return;

                if (this.User != null)
                {
                    this.User.LanguageId = value.LanguageId;
                    //IoC.Resolve<IEmployeeService>().UpdateCustomer(this.User);
                }

                CommonHelper.SetCookie("Payroll.EmployeeLanguage", value.LanguageId.ToString(), new TimeSpan(365, 0, 0, 0, 0));

                //reset cached value
                this._workingLanguage = null;
            }
        }
        /// <summary>
        /// Gets the last page for "Continue shopping" button on shopping cart page
        /// </summary>
        public string LastContinueShoppingPage
        {
            get
            {
                if ((HttpContext.Current.Session != null) && (HttpContext.Current.Session["Payroll.LastContinueShoppingPage"] != null))
                {
                    return HttpContext.Current.Session["Payroll.LastContinueShoppingPage"].ToString();
                }
                return string.Empty;
            }
            set
            {
                if ((HttpContext.Current != null) && (HttpContext.Current.Session != null))
                {
                    HttpContext.Current.Session["Payroll.LastContinueShoppingPage"] = value;
                }
            }
        }

        /// <summary>
        /// Sets the CultureInfo 
        /// </summary>
        /// <param name="culture">Culture</param>
        public void SetCulture(CultureInfo culture)
        {
            Thread.CurrentThread.CurrentCulture = culture;
            Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
        }
        
        #endregion
    }
}
